package com.qisimanxiang.dalaran.zuul.custom.ribbon;

import com.netflix.client.config.IClientConfig;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.zuul.constants.ZuulConstants;
import org.springframework.cloud.netflix.ribbon.apache.RibbonApacheHttpRequest;
import org.springframework.cloud.netflix.ribbon.apache.RibbonApacheHttpResponse;
import org.springframework.cloud.netflix.ribbon.apache.RibbonLoadBalancingHttpClient;
import org.springframework.cloud.netflix.ribbon.support.RibbonCommandContext;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.cloud.netflix.zuul.filters.route.apache.HttpClientRibbonCommand;
import org.springframework.cloud.netflix.zuul.filters.route.support.AbstractRibbonCommand;

/**
 * @author wangmeng
 * @date created in 3:50 下午 2019/9/17
 * @modified by
 */
public class CustomHttpClientRibbonCommand extends AbstractRibbonCommand<RibbonLoadBalancingHttpClient, RibbonApacheHttpRequest, RibbonApacheHttpResponse> {


    public CustomHttpClientRibbonCommand(RibbonLoadBalancingHttpClient client, RibbonCommandContext context, ZuulProperties zuulProperties) {
        super(client, context, zuulProperties);
    }

    public CustomHttpClientRibbonCommand(String commandKey, RibbonLoadBalancingHttpClient client, RibbonCommandContext context, ZuulProperties zuulProperties) {
        super(commandKey, client, context, zuulProperties);
    }

    public CustomHttpClientRibbonCommand(String commandKey, RibbonLoadBalancingHttpClient client, RibbonCommandContext context, ZuulProperties zuulProperties, FallbackProvider fallbackProvider) {
        super(commandKey, client, context, zuulProperties, fallbackProvider);
    }

    public CustomHttpClientRibbonCommand(String commandKey, RibbonLoadBalancingHttpClient client, RibbonCommandContext context, ZuulProperties zuulProperties, FallbackProvider fallbackProvider, IClientConfig config, int timeout) {

        this(getSetter(commandKey, zuulProperties, config, timeout), client, context, fallbackProvider, config);
    }

    protected CustomHttpClientRibbonCommand(Setter setter, RibbonLoadBalancingHttpClient client, RibbonCommandContext context, FallbackProvider fallbackProvider, IClientConfig config) {
        super(setter, client, context, fallbackProvider, config);
    }

    @Override
    protected RibbonApacheHttpRequest createRequest() throws Exception {
        return new RibbonApacheHttpRequest(this.context);
    }

    protected static Setter getSetter(final String commandKey,
                                      ZuulProperties zuulProperties, IClientConfig config, int timeout) {

        // @formatter:off
        Setter commandSetter = Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RibbonCommand"))
                .andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));
        final HystrixCommandProperties.Setter setter = createSetter(config, commandKey, zuulProperties);
        //FIXME 此处关闭
        setter.withCircuitBreakerEnabled(false);
        setter.withExecutionTimeoutEnabled(true);
        setter.withExecutionTimeoutInMilliseconds(timeout);
        //禁止 hystrix熔断
        setter.withCircuitBreakerSleepWindowInMilliseconds(0);
        //防止信号量获取失败
        setter.withExecutionIsolationSemaphoreMaxConcurrentRequests(1000);

        if (zuulProperties.getRibbonIsolationStrategy() == HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE) {
            final String name = ZuulConstants.ZUUL_EUREKA + commandKey + ".semaphore.maxSemaphores";
            // we want to default to semaphore-isolation since this wraps
            // 2 others commands that are already thread isolated
            final DynamicIntProperty value = DynamicPropertyFactory.getInstance()
                    .getIntProperty(name, zuulProperties.getSemaphore().getMaxSemaphores());
            setter.withExecutionIsolationSemaphoreMaxConcurrentRequests(value.get());
        } else if (zuulProperties.getThreadPool().isUseSeparateThreadPools()) {
            final String threadPoolKey = zuulProperties.getThreadPool().getThreadPoolKeyPrefix() + commandKey;
            commandSetter.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(threadPoolKey));
        }
        return commandSetter.andCommandPropertiesDefaults(setter);
        // @formatter:on
    }

}
